package com.bestcem.xm.qdes.service.impl;

import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.bestcem.xm.bi.grpc.v1.services.Column;
import com.bestcem.xm.common.core.exception.BusinessException;
import com.bestcem.xm.qdes.entity.QdesProject;
import com.bestcem.xm.qdes.entity.QdesProjectEntry;
import com.bestcem.xm.qdes.entity.QdesQstruct;
import com.bestcem.xm.qdes.entity.QdesQuestion;
import com.bestcem.xm.qdes.grpc.client.BiGrpcClient;
import com.bestcem.xm.qdes.grpc.client.DeliverGrpcClient;
import com.bestcem.xm.qdes.mapper.QdesProjectEntryMapper;
import com.bestcem.xm.qdes.mapper.QdesProjectMapper;
import com.bestcem.xm.qdes.mapper.QdesQstructMapper;
import com.bestcem.xm.qdes.mapper.QdesQuestionMapper;
import com.bestcem.xm.qdes.mq.dto.StatusDto;
import com.bestcem.xm.qdes.service.QdesMessageReceiverService;
import com.google.common.collect.Lists;
import lombok.NonNull;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.javatuples.Pair;
import org.springframework.stereotype.Service;
import org.springframework.util.ObjectUtils;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.stream.Collectors;

import static com.bestcem.xm.qdes.grpc.v1.services.ProjectEntryStatus.PROJECTENTRY_STATUS_ACTIVATED;
import static com.bestcem.xm.qdes.grpc.v1.services.ProjectEntryStatus.PROJECTENTRY_STATUS_FINISHED;
import static com.bestcem.xm.qdes.grpc.v1.services.ProjectStatus.PROJECT_STATUS_ACTIVATED;
import static com.bestcem.xm.qdes.grpc.v1.services.ProjectStatus.PROJECT_STATUS_CREATED_VALUE;
import static com.bestcem.xm.qdes.grpc.v1.services.ProjectStatus.PROJECT_STATUS_DELETED;
import static com.bestcem.xm.qdes.grpc.v1.services.ProjectStatus.PROJECT_STATUS_DELETED2;
import static com.bestcem.xm.qdes.grpc.v1.services.ProjectStatus.PROJECT_STATUS_FINISHED;

@Slf4j
@Service
@RequiredArgsConstructor
public class QdesMessageReceiverServiceImpl implements QdesMessageReceiverService {
    private @NonNull QdesProjectEntryMapper projectEntryMapper;
    private @NonNull QdesProjectMapper qdesProjectMapper;
    private @NonNull QdesQstructMapper qdesQstructMapper;
    private @NonNull QdesQuestionMapper qdesQuestionMapper;

    private @NonNull DeliverGrpcClient deliverGrpcClient;
    private @NonNull BiGrpcClient biGrpcClient;

    @Override
    public void projectUpdated(StatusDto msg) {
        // 投放、预警模块修改设置会调用
        String projectId = msg.getProjectId();
        // 项目状态随问卷状态变化
        Integer projStatus = msg.getCurrent();
        Integer status = null;
        LambdaUpdateWrapper<QdesProjectEntry> updateWrapper = new LambdaUpdateWrapper<>();
        if (projStatus != null) {
            if (PROJECT_STATUS_ACTIVATED.getNumber() == projStatus) {
                status = PROJECTENTRY_STATUS_ACTIVATED.getNumber();
            } else if (Arrays.asList(PROJECT_STATUS_FINISHED.getNumber(), PROJECT_STATUS_DELETED.getNumber(),
                    PROJECT_STATUS_DELETED2.getNumber()).contains(projStatus)) {
                status = PROJECTENTRY_STATUS_FINISHED.getNumber();
            }
        }
        if (status != null) {
            QdesProjectEntry update = new QdesProjectEntry();
            update.setStatus(status);
            update.setUpdatedDt(LocalDateTime.now());

            List<QdesProjectEntry> entries = projectEntryMapper.selectList(new LambdaQueryWrapper<QdesProjectEntry>()
                    .eq(QdesProjectEntry::getProjectId, projectId));
            if (CollectionUtils.isNotEmpty(entries)) {
                updateWrapper.in(QdesProjectEntry::getId, entries.stream().map(QdesProjectEntry::getId).distinct()
                        .collect(Collectors.toList()));
                projectEntryMapper.update(update, updateWrapper);
            }
        }
    }

    @Override
    public void projectDeletedShare(JSONObject dto) {
        //删除项目分享时，从免打扰中删除对应的项目
        JSONArray user_ids = dto.getJSONArray("user_ids");
        if (ObjectUtils.isEmpty(user_ids)) {
            return;
        }
        String survey_id = dto.getString("project_id");
        List<String> project_ids = qdesProjectMapper.selectList(new LambdaQueryWrapper<QdesProject>().in(QdesProject::getCreator, user_ids))
                .stream().map(QdesProject::getId).collect(Collectors.toList());
        //从所拥有的项目中删除
        deliverGrpcClient.projectDeletedShare(project_ids, survey_id);
    }

    @Override
    public void saveQuestionColumn(JSONObject dto) {
        //给项目列表页统计信息使用
        //在BI创建/更新完问卷数据源的worktable、column后在问卷模块记录worktable_id/column等信息
        //"first_sat_col": 第一个满意度题的col,
        //"first_nps_col": 第一个nps题的col,
        //"cal_score": 满意度题需要计算的选项值列表, 1个的时候取100%, 2-4个选项取TOP1, >=5取TOP2
        //"seq_col_id": seq列的column_id,
        //{"project_id":"str","worktable_id":"str"}
        log.info("Now to saveQuestionColumn, dto = {}", dto.toJSONString());
        QdesProject project = qdesProjectMapper.selectById(dto.getString("project_id"));
        if (project == null || Objects.equals(project.getStatus(), PROJECT_STATUS_CREATED_VALUE)) {
            return;
        }
        Pair<String, String> ret = getFirstSatisfActionNpsGid(project);
        String first_sat_gid = ret.getValue0();
        String first_nps_gid = ret.getValue1();
        String first_sat_col = "";
        String first_nps_col = "";
        String seq_col_id = "";
        String first_nps_col_id = "";
        String first_sat_col_id = "";
        List<Integer> cal_score = new ArrayList<>();// 满意度需要计算的值
        List<Column> columnList = biGrpcClient.listColumn(dto.getString("worktable_id"));
        if (columnList != null) {
            for (Column column : columnList) {
                if (StringUtils.isEmpty(first_sat_col) && first_sat_gid != null && first_sat_gid.equals(column.getCol().split("_")[0])) {
                    first_sat_col = column.getCol();
                    first_sat_col_id = column.getId();
                }
                if (StringUtils.isEmpty(first_nps_col) && first_nps_gid != null && first_nps_gid.equals(column.getCol().split("_")[0])) {
                    first_nps_col = column.getCol();
                    first_nps_col_id = column.getId();
                }
                if (StringUtils.isEmpty(seq_col_id) && "seq".equals(column.getCol())) {
                    seq_col_id = column.getId();
                }
            }
        }

        QdesQstruct qstruct = qdesQstructMapper.selectOne(
            new QueryWrapper<QdesQstruct>().lambda()
                .eq(QdesQstruct::getProjectId, project.getId())
                .eq(QdesQstruct::getVersion, project.getReleaseVer())
                .last("limit 1")
        );

        if (StringUtils.isNotEmpty(first_sat_gid)) {
            QdesQuestion question = qdesQuestionMapper.selectOne(
                new QueryWrapper<QdesQuestion>().lambda()
                    .eq(QdesQuestion::getStructId, qstruct.getId())
                    .eq(QdesQuestion::getGid, first_sat_gid)
                    .last("limit 1")
            );
            JSONObject dataJs = JSONObject.parseObject(question.getData());
            dataJs = dataJs == null ? new JSONObject() : dataJs;
            int sn = 0;
            int score_items_num = 0;
            if ("evaluation".equals(dataJs.getString("qtype"))) {
                JSONArray scoreList = Optional.ofNullable(dataJs.getJSONObject("current_template")).orElse(new JSONObject()).getJSONArray("scoreList");
                scoreList = scoreList == null ? new JSONArray() : scoreList;
                sn = scoreList.size();
                score_items_num = scoreList.size();
            } else {
                // 有满意度题，但是没有选项
                if (dataJs.get("items") != null) {
                    JSONArray score_range = dataJs.getJSONArray("score_range");
                    if (score_range != null) {
                        score_items_num = score_range.getInteger(1) - score_range.getInteger(0) + 1;
                        sn = score_range.getInteger(1);
                    }
                }
            }
            cal_score = getCalScore(score_items_num, sn);
        }

        LambdaUpdateWrapper<QdesProject> updateWrapper = new LambdaUpdateWrapper<>();
        //构造查询条件-更新
        JSONObject worktableJs = new JSONObject();
        worktableJs.put("worktable_id", dto.get("worktable_id"));
        worktableJs.put("first_sat_col", first_sat_col);
        worktableJs.put("first_nps_col", first_nps_col);
        worktableJs.put("cal_score", cal_score);
        worktableJs.put("seq_col_id", seq_col_id);
        worktableJs.put("first_nps_col_id", first_nps_col_id);
        worktableJs.put("first_sat_col_id", first_sat_col_id);
        updateWrapper.set(QdesProject::getWorktableInfo, worktableJs.toJSONString())
            .eq(QdesProject::getId, dto.getString("project_id"));
        qdesProjectMapper.update(null, updateWrapper);
    }

    // 计算逻辑：
    //            1个的时候取100%, 2-4个选项取TOP1, >=5取TOP2
    //            例如打分题分数设置了0 - 4
    //            则sn_count = 5，sn = 4
    //            :param sn_count: 选项总数
    //            :param sn: 最大选项值
    private List<Integer> getCalScore(int sn_count, int sn) {
        List<Integer> scores = new ArrayList<>();
        if (sn_count == 0) {
            return scores;
        }
        if (sn_count >= 5) {
            scores.add(sn -1);
            scores.add(sn);
            return scores;
        } else {
            // 即使只有一个的情况仍然可以取sn
            scores.add(sn);
            return scores;
        }
    }

    private Pair<String, String> getFirstSatisfActionNpsGid(QdesProject project) {
        QdesQstruct qstruct = qdesQstructMapper.selectOne(
                new QueryWrapper<QdesQstruct>().lambda()
                        .eq(QdesQstruct::getProjectId, project.getId())
                        .eq(QdesQstruct::getVersion, project.getReleaseVer())
                        .last("limit 1")
        );
        if (qstruct == null) {
            log.error(String.format("qstruct[projectID=%s,version=%s] not found", project.getId(), project.getReleaseVer()));
            throw new BusinessException(String.format("qstruct[projectID=%s,version=%s] not found", project.getId(), project.getReleaseVer()));
        }

        List<String> sat_gids = new ArrayList<>();
        List<String> nps_gids = new ArrayList<>();
        //HashMap<String, QdesQuestion> gid_question_map = new HashMap<>();
        //获取出 判断满意度和nps的questiions
        List<QdesQuestion> questions = getScoreQuestions(qstruct.getId());
        questions.forEach(question -> {
            JSONObject qdata = JSONObject.parseObject(question.getData());
            String custom_qtype = qdata.getString("custom_qtype");
            String gid = qdata.getString("gid");
            //gid_question_map.put(gid, question);
            if (Objects.equals(custom_qtype, "nps")) {
                nps_gids.add(gid);
            } else {
                sat_gids.add(gid);
            }
        });

        //获取第一个满意度和nps题
        return getFirstSatisfActionNpsGid(qstruct.getData(), sat_gids, nps_gids);
    }

    private Pair<String, String> getFirstSatisfActionNpsGid(String datastr, List<String> satisfaction_gids, List<String> nps_gids) {
        log.info("getFirstSatisfActionNpsGid 入参:qstruct.data={},satisfaction_gids={},nps_gids={}", datastr, JSON.toJSONString(satisfaction_gids), JSON.toJSONString(nps_gids));
        //获取第一个满意度的题型gid,和nps题型gid
        String first_satisfaction_gid = null, first_nps_gid = null;
        JSONObject data = JSONObject.parseObject(datastr);
        JSONArray itemsList = data.getJSONArray("items");
        Objects.requireNonNull(itemsList);
        for (int i = 0; i < itemsList.size(); i++) {
            JSONObject item = itemsList.getJSONObject(i);
            if (StrUtil.equals(item.getString("type"), "G")) {
                JSONArray tmparry = item.getJSONArray("items");
                Objects.requireNonNull(tmparry);
                for (int j = 0; j < tmparry.size(); j++) {
                    JSONObject tmp = tmparry.getJSONObject(j);
                    if (ObjectUtils.isEmpty(first_satisfaction_gid) && satisfaction_gids.contains(tmp.getString("gid"))) {
                        first_satisfaction_gid = tmp.getString("gid");
                    }
                    if (ObjectUtils.isEmpty(first_nps_gid) && nps_gids.contains(tmp.getString("gid"))) {
                        first_nps_gid = tmp.getString("gid");
                    }
                }
            } else if (StrUtil.equals(item.getString("type"), "Q")) {
                if (ObjectUtils.isEmpty(first_satisfaction_gid) && satisfaction_gids.contains(item.getString("gid"))) {
                    first_satisfaction_gid = item.getString("gid");
                }
                if (ObjectUtils.isEmpty(first_nps_gid) && nps_gids.contains(item.getString("gid"))) {
                    first_nps_gid = item.getString("gid");
                }
            }
        }
        return Pair.with(first_satisfaction_gid, first_nps_gid);
    }

    private List<QdesQuestion> getScoreQuestions(String qstruct_id) {
        //获取打分题、评价题、游标打分题的题型
        List<QdesQuestion> questionList = qdesQuestionMapper.selectList(new QueryWrapper<QdesQuestion>().lambda()
                .eq(QdesQuestion::getStructId, qstruct_id));
        return questionList.stream().filter(item -> {
            JSONObject dict = JSONObject.parseObject(item.getData());
            return !ObjectUtils.isEmpty(dict) && Lists.newArrayList("star_score", "evaluation", "cursor_score", "nps").contains(dict.getString("custom_qtype"));
        }).collect(Collectors.toList());
    }
}
